Published 2006-02-28 09:50:42
GtkWidget * gnome_canvas_new_aa(void);becomes
extern(C)
{
GtkWidget* function() gnome_canvas_new_aa;
}
enabling you to call the function in D using
GtkWidget *canvas;Since GtkWidget is defined in the DUI package, I had to add a few imports:
canvas = gnome_canvas_new_aa();
private import dui.DUI;DUI provides wrappers to a D style interface for GTK, however, to make things easier to start with, I used the native C methods to call gtk, and mixed them up a bit with the gtk object wrapper, so creating a new window became:
private import def.Types;
private import def.Constants;
private import lib.gtk;
GtkWidget *app;
app = gtk_window_new (GtkWindowType.TOPLEVEL);
gtk_window_fullscreen( cast(GtkWindow*) app );
/dmd/bin/dmd -gc -c -O -od. canvas.dHowever, when it came to linking I took me a while to understand why linking it to the gnomecanvas lib's caused the application to segfault on the first gtk call.
-I/dmd/src/phobos:/usr/src/dyndui/src:/usr/src/dool/src/
gcc canvas.o -o canvas -L/usr/src/dool -ldool -L/usr/src/dyndui -lduiWhat I failed to understand until I dug into the DUI code, was that libgtk was being dynamically loaded and linked by DUI. so linking it here caused the library to be doublely linked, and hence segfault.
-lphobos -lstdc++ -ldl -pthread -L/usr/src/dool -ldool -lphobos
`pkg-config --libs libgnomecanvas-2.0`
gcc canvas.o -o canvas -L/usr/src/dool -ldool -L/usr/src/dyndui -ldui
-lphobos -lstdc++ -ldl -pthread -L/usr/src/dool -ldool -lphobos
Adding the symbol list is quite easy, first define an array of symbols to send to the linker.
Symbol[] GnomeCanvasLinks = [
{ "gnome_canvas_new_aa", cast(void**)& gnome_canvas_new_aa } ,
.....
];
Then define a constructor (and destructor) for the file:
static this()
{
gnomecanvas_Linker = new Linker( "libgnomecanvas-2.so" );
gnomecanvas_Linker.link( GnomeCanvasLinks );
}
static ~this()
{
delete gnomecanvas_Linker;
}
Then define a constructor (and destructor) for the file:
gnome_canvas_item_new(GnomeCanvasGroup* parent,
GType type, gchar* first_arg_name,...)
gnome_canvas_item_new(root, gnome_cavnas_rect_get_type(),
"x1", 12.0,
"y1", 12.0, ........etc....
This is a function call that uses varargs, and sends a variety of types down the line to the constructor. Unfortunatly although D will generally autotypecast data to normal function calls, it is asking a bit much for it to guess what random data you may be sending to this varargs function.
To get around this, I eventually worked out that sending null as first_arg_name, and the first argument could be used to create the object.this.item = gnome_canvas_item_new ( parent,type,null,null);
After that, using the gnome_canvas_item_set, and correctly casting the data to the correct type can be used to set the values:
gnome_canvas_item_set(this.item, cast(char*) "x1", (cast(double) 123.0);Since D is a wonderfull hybrid of functional and object orientated language, I decided to try out an object to represent this.
class CanvasItem {Set's up the constructor wrapper around the CanvasItem.
GnomeCanvasItem* item;
this(GnomeCanvasGroup* parent, GType type)
{
this.item = gnome_canvas_item_new ( parent,type,null,null);
}
void set(char[] k, char[] v)
{
gnome_canvas_item_set(this.item, cast(char *)k, cast(char *)v,null);
}
void set(char[] k, double v)
{
gnome_canvas_item_set(this.item, cast(char *)k, v,null);
}
void set(char[] k, int v)
{
gnome_canvas_item_set(this.item, cast(char *)k, v,null);
}
However, using this method I would still have to keep calling
canvas_item.set("x1",123.0);
and make sure it was sending the right type for each attribute, so I had a go at using D's setter syntax, by defining a method with the same name as the property you intend to make available, you can make it perform a set operation.
void x1(double v) { this.set("x1", v); }
void x2(double v) { this.set("x2", v); }
Meaning that you can now write:
canvas_item = new CanvasItem(parent);
canvas_item.x1 = 123;
canvas_item.y1 = 456;
This follows through to setting colours and fonts
void font(char[] v) { this.set("font", v); }I even got clever allowing fill_color_rgba to accept "#ffccff" string style values, rather than 0xffccff00, by overloading the setter to accept string types:
void fillColor(char[] v) { this.set("fill-color", v); }
}
void fill_color_rgba(double v)
{
this.set("fill_color_rgba", cast(int) v);
}
void fill_color_rgba(char[] v)
{
if (v == "none") {
return;
}
int c=0;
int mult = 0x10000000;
for (int i = 1; i < 7; i++) {
int p = ifind(hexdigits, v[i]);
c += (p > -1) ? mult * p : 0;
mult = mult / 0x10;
}
c+=0xff;
this.set("fill_color_rgba", cast(int) c);
}
I'm sure given more time, that could be even cleaner :)
One of the things that is so beautiful about D, is that the standard library, phobos, is so small and compact, which makes it very easy to learn, and quickly use.
to use the library you just have to import the namespace (or you could just use the full path in your code.)
private import dool.xml.xml;or
XmlParser x = new XmlParser();
XmlDocument xmldoc = x.parse(testdata);
auto x = new dool.xml.xml.XmlParser();should work (well I havent tested the second, but it is a little more readable, as the import line ends up at the top of the file.
auto xmldoc = x.parse(testdata);
File f = new File( r"/tmp/data.svg", FileMode.In );almost as simple as file_get_contents(), and since D cleans up the File handle at the end of the method it's in, you dont really need to delete f to close the file handle. [slight correction here thanks to Regan Heath] the destructor will not be called unless f is defined as type auto, and there is another method read(), which can read the whole file in one go.
while (!f.eof()) {
testdata ~= f.readString( f.available());
}
char[] testdata = cast(char[]) std.file.read( r"/tmp/data.svg");
CanvasItem ci = new CanvasItem(parent,gnome_canvas_text_get_type());atof and atoi provide the conversion, and since D supports string based switch case, looping through the style component of the SVG file is quite simple. as shown here.
ci.x = atof(node.getAttribute("x").value);
ci.y = atof(node.getAttribute("y").value);
void setStyle(CanvasItem ci)Well, my little SVG renderer can just render rectangles and text at present, but it's interesting to see how simple everything comes together, and how a language designed properly can really make a huge difference.
{
char[][] bits = split(this.currentStyle,";");
foreach(int i, char[] kv; bits) {
if (-1 == find(kv,":")) {
continue;
}
char[][] kv_ar = split(kv,":");
char [] k = kv_ar[0];
char [] v = kv_ar[1];
printf("set: %.*s=> %.*s\n", k,v);
switch(k) {
case "font-family": ci.font=v; break;
case "font-size": ci.size = atoi(replace(v,"px","")); break;
case "font-weight":
if (v == "bold") {
ci.weight = 800;
}
break;
case "fill": ci.fill_color_rgba = v; break;
default: break;
}
}
}